package com.ssy.lingxi.order.serviceimpl.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.MemberAndRoleIdDTO;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberFeignRightByOrderVO;
import com.ssy.lingxi.order.api.model.vo.request.OrderExpressFeeConfigUpdateVO;
import com.ssy.lingxi.order.api.model.vo.request.OrderScoreConfigUpdateVO;
import com.ssy.lingxi.order.api.model.vo.response.OrderExpressFeeConfigDetailVO;
import com.ssy.lingxi.order.api.model.vo.response.OrderFreeExpressConfigVO;
import com.ssy.lingxi.order.api.model.vo.response.OrderScoreConfigDetailVO;
import com.ssy.lingxi.order.api.model.vo.response.OrderScoreConfigVO;
import com.ssy.lingxi.order.entity.BaseOrderConfigDO;
import com.ssy.lingxi.order.entity.QBaseOrderConfigDO;
import com.ssy.lingxi.order.model.bo.OrderConfigBO;
import com.ssy.lingxi.order.model.constant.BaseOrderConfigEnum;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.vo.basic.request.OrderLrcItemVO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderLrcVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderLrcDetailVO;
import com.ssy.lingxi.order.repository.BaseOrderConfigRepository;
import com.ssy.lingxi.order.service.feign.IMemberFeignService;
import com.ssy.lingxi.order.service.web.IOrderParamConfigService;
import com.ssy.lingxi.order.utils.NumberUtil;
import com.ssy.lingxi.report.api.enums.CommonBooleanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *  系统能力 - 参数配置-[积分相关][运费相关]实现类
 * @author ds
 * @date 2022/2/24
 * @version 2.0.0
 */
@Slf4j
@Service
public class OrderParamConfigServiceImpl implements IOrderParamConfigService {
    @Resource
    private BaseOrderConfigRepository orderConfigRepository;


    @Resource
    private JPAQueryFactory jpaQueryFactory;
    @Resource
    private IMemberFeignService memberFeignService;

    @Override
    public Wrapper<OrderScoreConfigDetailVO> getScoreConfig(UserLoginCacheDTO loginUser) {

        BaseOrderConfigDO baseOrderConfigDO = orderConfigRepository.findByTypeAndMemberIdAndMemberRoleId(BaseOrderConfigEnum.DEDUCTION_SCORE_OF_ORDER.getCode(), loginUser.getMemberId(), loginUser.getMemberRoleId());
        OrderScoreConfigDetailVO respVO=null;
        if(baseOrderConfigDO!=null){
            respVO=new OrderScoreConfigDetailVO();
            OrderConfigBO configBO = baseOrderConfigDO.getConfigBO();
            respVO.setId(baseOrderConfigDO.getId());
            respVO.setStatus(baseOrderConfigDO.getStatus());
            respVO.setDeductionRate(configBO.getDeductionRate());
            respVO.setUserScoreLimit(configBO.getUserScoreLimit());
        }
        return Wrapper.success(respVO);
    }

    private boolean isNotSameMember(UserLoginCacheDTO loginUser, Long memberId, Long roleId){
        return !loginUser.getMemberId().equals(memberId) || !loginUser.getMemberRoleId().equals(roleId);
    }

    private BaseOrderConfigDO checkOrderConfig(Long id,UserLoginCacheDTO loginUser,BaseOrderConfigEnum configEnum){
        BaseOrderConfigDO baseOrderConfigDO;
        if(id!=null){
            baseOrderConfigDO = orderConfigRepository.findById(id).orElse(null);
            if(baseOrderConfigDO==null|| isNotSameMember(loginUser, baseOrderConfigDO.getMemberId(), baseOrderConfigDO.getMemberRoleId())){
                throw new BusinessException(ResponseCode.DATA_AUTH_NOT_ALLOWED);
            }
        }else {
            baseOrderConfigDO = orderConfigRepository.findByTypeAndMemberIdAndMemberRoleId(configEnum.getCode(), loginUser.getMemberId(), loginUser.getMemberRoleId());
            if(baseOrderConfigDO==null){
                baseOrderConfigDO=new BaseOrderConfigDO();
                baseOrderConfigDO.setType(configEnum.getCode());
                baseOrderConfigDO.setMemberId(loginUser.getMemberId());
                baseOrderConfigDO.setMemberRoleId(loginUser.getMemberRoleId());
            }else if(isNotSameMember(loginUser, baseOrderConfigDO.getMemberId(), baseOrderConfigDO.getMemberRoleId())){
                throw new BusinessException(ResponseCode.DATA_AUTH_NOT_ALLOWED);
            }
        }
        log.info("更新前：baseOrderConfigDO：{}", JSONUtil.toJsonStr(baseOrderConfigDO));
        return baseOrderConfigDO;
    }

    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updateScoreConfig(UserLoginCacheDTO loginUser, OrderScoreConfigUpdateVO updateVO) {
        //基础校验
        BaseOrderConfigDO baseOrderConfigDO=checkOrderConfig(updateVO.getId(),loginUser,BaseOrderConfigEnum.DEDUCTION_SCORE_OF_ORDER);
        //校验必填值
        if(CommonBooleanEnum.YES.getCode().equals(updateVO.getStatus())){
            if(!(NumberUtil.notNullAndPositive(updateVO.getDeductionRate())&&NumberUtil.notNullAndPositive(updateVO.getUserScoreLimit()))){
                return Wrapper.fail(ResponseCode.ORDER_CONFIG_SCORE_PARAM_ERROR);
            }
        }
        //更新
        baseOrderConfigDO.setStatus(updateVO.getStatus());
        OrderConfigBO configBO =new OrderConfigBO();
        configBO.setDeductionRate(updateVO.getDeductionRate());
        configBO.setUserScoreLimit(updateVO.getUserScoreLimit());
        baseOrderConfigDO.setConfigBO(configBO);
        orderConfigRepository.saveAndFlush(baseOrderConfigDO);
        log.info("updateScoreConfig 更新后：configDO：{}", JSONUtil.toJsonStr(baseOrderConfigDO));
        return Wrapper.success();
    }

    @Override
    public Wrapper<OrderExpressFeeConfigDetailVO> getExpressFeeConfig(UserLoginCacheDTO loginUser) {
        BaseOrderConfigDO baseOrderConfigDO = orderConfigRepository.findByTypeAndMemberIdAndMemberRoleId(BaseOrderConfigEnum.FREE_EXPRESS_CONDITION.getCode(), loginUser.getMemberId(), loginUser.getMemberRoleId());
        OrderExpressFeeConfigDetailVO respVO=null;
        if(baseOrderConfigDO!=null){
            respVO=new OrderExpressFeeConfigDetailVO();
            OrderConfigBO configBO = baseOrderConfigDO.getConfigBO();
            respVO.setId(baseOrderConfigDO.getId());
            respVO.setStatus(baseOrderConfigDO.getStatus());
            respVO.setOrderAmount(configBO.getOrderAmount());
        }
        return Wrapper.success(respVO);
    }

    @Override
    public Wrapper<Void> updateExpressFeeConfig(UserLoginCacheDTO loginUser, OrderExpressFeeConfigUpdateVO updateVO) {
        BaseOrderConfigDO baseOrderConfigDO=checkOrderConfig(updateVO.getId(),loginUser,BaseOrderConfigEnum.FREE_EXPRESS_CONDITION);
        //校验必填值
        if(CommonBooleanEnum.YES.getCode().equals(updateVO.getStatus())){
            if(!NumberUtil.notNullAndPositive(updateVO.getOrderAmount())){
                return Wrapper.fail(ResponseCode.ORDER_CONFIG_EXPRESS_FEE_PARAM_ERROR);
            }
        }
        //更新
        baseOrderConfigDO.setStatus(updateVO.getStatus());
        OrderConfigBO configBO =new OrderConfigBO();
        configBO.setOrderAmount(updateVO.getOrderAmount());
        baseOrderConfigDO.setConfigBO(configBO);
        orderConfigRepository.saveAndFlush(baseOrderConfigDO);
        log.info("updateExpressFeeConfig 更新后：configDO：{}", JSONUtil.toJsonStr(baseOrderConfigDO));
        return Wrapper.success();
    }

    private List<BaseOrderConfigDO> batchOrderParamConfig(List<MemberAndRoleIdDTO> memberAndRoleIdDTOS,BaseOrderConfigEnum type){
        QBaseOrderConfigDO orderConfigDO=QBaseOrderConfigDO.baseOrderConfigDO;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        //状态
        booleanBuilder.and(orderConfigDO.status.eq(CommonBooleanEnum.YES.getCode()));
        //类型
        if(type!=null){
            booleanBuilder.and(orderConfigDO.type.eq(type.getCode()));
        }
        //构造多字段查询条件
        Predicate[] predicates=memberAndRoleIdDTOS.stream().map(o -> orderConfigDO.memberId.eq(o.getMemberId()).and(orderConfigDO.memberRoleId.eq(o.getRoleId()))).toArray(Predicate[]::new);

        return jpaQueryFactory
                .select(Projections.bean(BaseOrderConfigDO.class,
                        orderConfigDO.memberId,
                        orderConfigDO.memberRoleId,
                        orderConfigDO.configBO))
                .from(orderConfigDO)
                .where(booleanBuilder)
                .where(ExpressionUtils.anyOf(predicates))
                .fetch();
    }

    public List<OrderFreeExpressConfigVO> getOrderFreeExpressConfigList(List<MemberAndRoleIdDTO> memberAndRoleIdDTOS){
        List<BaseOrderConfigDO> baseOrderConfigDOS =batchOrderParamConfig(memberAndRoleIdDTOS,BaseOrderConfigEnum.FREE_EXPRESS_CONDITION);
        //转换
        if(CollectionUtil.isNotEmpty(baseOrderConfigDOS)){
            return baseOrderConfigDOS.stream().map(o ->{
                OrderFreeExpressConfigVO resp=new OrderFreeExpressConfigVO();
                resp.setMemberId(o.getMemberId());
                resp.setRoleId(o.getMemberRoleId());
                resp.setOrderAmount(o.getConfigBO().getOrderAmount());
                return resp;
            }).collect(Collectors.toList());
        }
        return Collections.EMPTY_LIST;
    }

    public List<OrderScoreConfigVO> getOrderScoreConfigList(List<MemberAndRoleIdDTO> memberAndRoleIdDTOS){
        List<BaseOrderConfigDO> baseOrderConfigDOS =batchOrderParamConfig(memberAndRoleIdDTOS,BaseOrderConfigEnum.DEDUCTION_SCORE_OF_ORDER);
        //转换
        if(CollectionUtil.isNotEmpty(baseOrderConfigDOS)){
            return baseOrderConfigDOS.stream().map(o ->{
                OrderScoreConfigVO resp=new OrderScoreConfigVO();
                resp.setMemberId(o.getMemberId());
                resp.setRoleId(o.getMemberRoleId());
                resp.setDeductionRate(o.getConfigBO().getDeductionRate());
                resp.setUserScoreLimit(o.getConfigBO().getUserScoreLimit());
                return resp;
            }).collect(Collectors.toList());
        }
        return Collections.EMPTY_LIST;
    }

    /**
     * 扣除剩余抵扣金额（每个会员（含平台）1角）
     * 当积分足够抵扣订单金额时，需余下1角用于支付
     * @param realAmount
     * @return
     */
    private BigDecimal calcSurplusDeductionAmount(BigDecimal realAmount){
        BigDecimal surplusAmount = BigDecimal.valueOf(OrderServiceContants.SURPLUS_DEDUCTION_AMOUNT);
        boolean gtSurplus = realAmount.compareTo(surplusAmount) > 0;
        if(gtSurplus){
            realAmount=realAmount.subtract(surplusAmount);
        }
        return realAmount;
    }

    /**
     * 计算抵扣积分（向下取整）
     * 例：0.1/0.5 返回0；1.1/1.8返回1，以此类推
     * @param point
     * @return
     */
    private BigDecimal calcDeductionPoint(BigDecimal point){
        return point.setScale(0, RoundingMode.DOWN);
    }

    public List<OrderLrcDetailVO> getOrderScoreAndDeductionConfigList(Long subMemberId, Long subRoleId, OrderLrcVO lrcVO){
        List<MemberAndRoleIdDTO> memberAndRoleIdDTOS = lrcVO.getItemList().stream().map(o -> {
            MemberAndRoleIdDTO dto = new MemberAndRoleIdDTO();
            dto.setMemberId(o.getVendorMemberId());
            dto.setRoleId(o.getVendorRoleId());
            return dto;
        }).collect(Collectors.toList());
        //1.查询采购商在平台与供应商店铺的可用积分【feign会员服务】
        Wrapper<List<MemberFeignRightByOrderVO>> listWrapper = memberFeignService.batchMemberPriceRightForOrder(subMemberId, subRoleId, memberAndRoleIdDTOS);
        if(listWrapper.getCode()!=ResponseCode.SUCCESS.getCode()||CollectionUtil.isEmpty(listWrapper.getData())){
            Wrapper.success(Collections.emptyList());
        }
        //得到平台会员信息
        List<MemberFeignRightByOrderVO> ptLrcList = listWrapper.getData().stream().filter(o -> o.getRelType() == 0).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(ptLrcList)){
            MemberFeignRightByOrderVO ptLrc = ptLrcList.get(0);
            //加入平台消息->查询订单可抵扣金额
            memberAndRoleIdDTOS.add(new MemberAndRoleIdDTO(ptLrc.getUpperMemberId(),ptLrc.getUpperRoleId()));
            //获取入参平台金额用
            OrderLrcItemVO orderLrcItemVO = new OrderLrcItemVO();
            orderLrcItemVO.setVendorMemberId(ptLrc.getUpperMemberId());
            orderLrcItemVO.setVendorRoleId(ptLrc.getUpperRoleId());
            orderLrcItemVO.setPlatformAmount(lrcVO.getItemList().get(0).getPlatformAmount());
            orderLrcItemVO.setMemberAmount(BigDecimal.ZERO);
            lrcVO.getItemList().add(orderLrcItemVO);
        }
        //过滤会员积分大于0的
        Map<String, MemberFeignRightByOrderVO> pointsMap = listWrapper.getData().stream().filter(o ->NumberUtil.notNullAndPositive(o.getCurrentPoint())).collect(Collectors.toMap(k -> k.getUpperMemberId() + ":" + k.getUpperRoleId(), v -> v, (v1, v2) -> v1));

        //2.查询供应商会员积分抵扣订单金额开启状态
        Map<String, OrderLrcItemVO> orderLrcMap = lrcVO.getItemList().stream().collect(Collectors.toMap(k -> k.getVendorMemberId() + ":" + k.getVendorRoleId(), v -> v, (v1, v2) -> v1));
        List<OrderScoreConfigVO> orderScoreConfigList = getOrderScoreConfigList(memberAndRoleIdDTOS);
        List<OrderLrcDetailVO> respList =Collections.EMPTY_LIST;
        if(CollectionUtil.isNotEmpty(orderScoreConfigList)){
            respList = orderScoreConfigList.stream()
                    .filter(o ->(pointsMap.get(o.getMemberId() + ":" + o.getRoleId())!=null)&&orderLrcMap.get(o.getMemberId() + ":" + o.getRoleId())!=null)
                    .map(o -> {
                OrderLrcDetailVO vo = new OrderLrcDetailVO();
                vo.setVendorMemberId(o.getMemberId());
                vo.setVendorRoleId(o.getRoleId());
                vo.setDeductionRate(o.getDeductionRate());
                vo.setUserScoreLimit(o.getUserScoreLimit());
                MemberFeignRightByOrderVO lrc = pointsMap.get(o.getMemberId() + ":" + o.getRoleId());
                vo.setCurrentPoint(lrc.getCurrentPoint());
                vo.setRelType(lrc.getRelType());
                vo.setVendorLogo(lrc.getUpperLogo());
                vo.setVendorName(lrc.getUpperName());
                OrderLrcItemVO orderLrcItemVO = orderLrcMap.get(o.getMemberId() + ":" + o.getRoleId());
                BigDecimal realAmount = orderLrcItemVO.getMemberAmount();
                if(lrc.getRelType()==0){
                    //平台
                    realAmount=orderLrcItemVO.getPlatformAmount();
                }
                //订单限额
                BigDecimal orderLimitAmount = o.getUserScoreLimit().divide(o.getDeductionRate(),3, RoundingMode.HALF_UP);
                //当前可用积分
                BigDecimal currentPoint = BigDecimal.valueOf(lrc.getCurrentPoint());
                //当前可用积分大于订单限购积分
                if(currentPoint.compareTo(o.getUserScoreLimit())>=0){
                    //订单金额大于订单最大抵扣金额
                    if(realAmount.compareTo(orderLimitAmount)>0){
                        BigDecimal point=o.getUserScoreLimit();
                        vo.setEnablePoint(point);
                        vo.setEnableDeductionAmount(point.divide(o.getDeductionRate(),3,RoundingMode.DOWN));
                    }else{
                        //足够抵扣订单金额
                        realAmount = calcSurplusDeductionAmount(realAmount);
                        BigDecimal point=calcDeductionPoint(realAmount.multiply(o.getDeductionRate()));
                        BigDecimal preDeductionAmount = point.divide(o.getDeductionRate(), 3, RoundingMode.HALF_UP);
                        if(preDeductionAmount.compareTo(realAmount)<0) {
                            realAmount=preDeductionAmount;
                        }
                        vo.setEnableDeductionAmount(realAmount);
                        vo.setEnablePoint(point);
                    }
                }else{
                    //订单金额转积分大于可用积分
                    if(realAmount.multiply(o.getDeductionRate()).compareTo(currentPoint)>0){
                        vo.setEnableDeductionAmount(currentPoint.divide(o.getDeductionRate(),3, RoundingMode.HALF_UP));
                        vo.setEnablePoint(currentPoint);
                    }else{
                        //足够抵扣订单金额
                        realAmount=calcSurplusDeductionAmount(realAmount);
                        BigDecimal point=calcDeductionPoint(realAmount.multiply(o.getDeductionRate()));
                        BigDecimal preDeductionAmount = point.divide(o.getDeductionRate(), 3, RoundingMode.HALF_UP);
                        if(preDeductionAmount.compareTo(realAmount)>0) {
                            preDeductionAmount=realAmount;
                        }
                        vo.setEnableDeductionAmount(preDeductionAmount);
                        vo.setEnablePoint(point);
                    }
                }
                return vo;
            }).collect(Collectors.toList());
        }
        return respList;
    }
}
